#region Copyright RenGuiYou. All rights reserved.

//=====================================================
// NeatlyFrameWork
// Author:      RenGuiyou
// Feedback: 	mailto:750539605@qq.com
//=====================================================

#endregion

using System;
using UnityEngine;
using UnityEngine.EventSystems;

namespace Neatly.UI
{
    public class NSlider : EmptyRaycast, IDragHandler, IPointerDownHandler, IPointerUpHandler
    {
        private float m_TweenTime = 0.5f;

        public enum Direction
        {
            LeftToRight,
            RightToLeft,
        }

        [SerializeField]
        private Direction m_Direction = Direction.LeftToRight;
        [SerializeField]
        private RectTransform m_FillRect;
        [SerializeField]
        private bool m_HasBar;
        [SerializeField]
        private float m_StartBorder;
        [SerializeField]
        private float m_EndBorder;

        private float m_Width;

        private float Width
        {
            get
            {
                if (m_Width == 0)
                {
                    m_Width = rectTransform.GetSizeDeltaX();
                }

                return m_Width;
            }
        }
        
        public Direction direction
        {
            get
            {
                return m_Direction;
            }
            set
            {
                if (!SetPropertyUtility.SetStruct(ref m_Direction, value))
                    return;
                UpdateVisuals();
            }
        }

        public RectTransform fillRect
        {
            get { return m_FillRect; }
            set { m_FillRect = value; }
        }

        [Range(0, 1)]
        [SerializeField]
        protected float m_Value;

        public float value
        {
            get { return GetValue(); }
        }

        private Action<float> m_OnValueChanged;
        private Action m_OnPointerDown;
        private Action m_OnPointerUp;
        
        protected override void Start()
        {
            base.Start();
            raycastTarget = m_HasBar;
        }

        public void AddOnValueChangedListener(Action<float> action)
        {
            m_OnValueChanged = action;
        }

        public void AddPointerListener(Action pointerDown, Action PointerUp)
        {
            m_OnPointerDown = pointerDown;
            m_OnPointerUp = PointerUp;
        }
        
        public void SetValue(float val)
        {
            if (val > 1)
            {
                val = 1;
            }
            else if (val < 0)
            {
                val = 0;
            }

            if (Math.Abs(m_Value - val) < float.Epsilon)
            {
                return;
            }

            m_Value = val;
            UpdateVisuals();
        }

        public void SetTweenTime(float time)
        {
            m_TweenTime = time;
        }

        public void TweenValue(float val)
        {
            UITween.SliderMove(this, val, m_TweenTime);
        }

        public float GetValue()
        {
            return m_Value;
        }

#if UNITY_EDITOR
        protected override void OnValidate()
        {
            UpdateVisuals();
        }
#endif
        private void UpdateVisuals()
        {
            UpdateFillRect();
        }

        private void UpdateFillRect()
        {
            if (!m_FillRect) return;
            float val = m_Value;
            switch (m_Direction)
            {
                case Direction.LeftToRight:
                    m_FillRect.anchorMin = Vector2.zero;
                    m_FillRect.anchorMax = new Vector2(val, 1);
                    break;
                case Direction.RightToLeft:
                    m_FillRect.anchorMin = new Vector2(1 - val, 0);
                    m_FillRect.anchorMax = Vector2.one;
                    break;
            }
        }

        public void OnPointerDown(PointerEventData eventData)
        {
            m_OnPointerDown?.Invoke();
            UpdateDrag(eventData);
        }

        public void OnPointerUp(PointerEventData eventData)
        {
            m_OnPointerUp?.Invoke();
        }

        public void OnDrag(PointerEventData eventData)
        {
            UpdateDrag(eventData);
        }

        void UpdateDrag(PointerEventData eventData)
        {
            if (!m_HasBar)
                return;
            Vector2 localCursor;
            if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, eventData.position,
                eventData.pressEventCamera, out localCursor))
                return;
            float val = 0;
            float curWidth = Width;
            if (m_HasBar)
            {
                curWidth = Width - m_StartBorder - m_EndBorder;
            }
            switch (m_Direction)
            {
                case Direction.LeftToRight:
                    val = (localCursor.x + curWidth / 2) / curWidth;
                    break;
                case Direction.RightToLeft:
                    val = (curWidth / 2 - localCursor.x) / curWidth;
                    break;
            }

            val = Mathf.Clamp01(val);
            if (m_HasBar)
            {
                val = ((Width - m_StartBorder - m_EndBorder)* val  + m_StartBorder) / Width;
            }
            SetValue(val);
            if (m_OnValueChanged != null)
            {
                m_OnValueChanged(val);
            }
        }
    }
}